/**
 * 多层同心圆
 */
import React, { useMemo, useRef, useState } from 'react';

import { useUpdateEffect } from 'ahooks';
import cs from 'classnames';
import type { EChartsType, PieSeriesOption } from 'echarts';

import { px, px2rem } from '@/utils';

import Chart, { ChartOption, ChartProps } from '../index';
import styles from './index.module.scss';

export type MultiRingData = {
  name: string;
  value: number;
};

export type MultiRingProps = Partial<ChartProps> & {
  data: MultiRingData[];
  wrapClassName?: string;
  legendClassName?: string;
  legend?: (
    data: MultiRingData & {
      index: number;
      selected: boolean;
      color: string;
      colorNode: React.ReactElement;
      percent: number;
    }
  ) => React.ReactElement;
};

const MultiRing: React.FC<MultiRingProps> = ({
  data: propsData,
  option: propsOption,
  extra: propsExtra,
  onChartReady: propsOnChartReady,
  wrapClassName: propsWrapClassName,
  className: propsClassName,
  legendClassName: propsLegendClassName,
  legend: propsLegend,
  ...rest
}) => {
  const instance = useRef<EChartsType>();
  const [selectedLegends, setSelectedLegends] = useState<string[]>(propsData.map((v) => v.name));
  const [colors, setColors] = useState<string[]>([]);
  const [dom, setDom] = useState<HTMLElement>();

  useUpdateEffect(() => {
    setSelectedLegends(propsData.map((v) => v.name));
  }, [propsData]);

  const valuebyName = useMemo(() => {
    return propsData.reduce<Record<string, MultiRingData>>((acc, cur) => {
      acc[cur.name] = cur;

      return acc;
    }, {});
  }, [propsData]);

  const total = useMemo(() => {
    return propsData.reduce<number>((acc, cur) => acc + cur.value, 0);
  }, [propsData]);

  const option: ChartOption = useMemo(() => {
    const res: ChartOption = Object.assign(
      {},
      {
        legend: {
          show: false
        },
        series: []
      } as ChartOption,
      propsOption
    );

    if (!dom) {
      return res;
    }

    const count = propsData.length;
    // 最大的百分比0-1
    const maxPercent = 0.7;
    // 最小百分比0-1
    const minPercent = 0.2;
    // 容器宽
    const width = dom.offsetWidth;
    // 容器高
    const height = dom.offsetHeight;
    // 容器最小尺寸
    const size = Math.min(width, height) * maxPercent;
    // 线条宽度
    const lineWidth = px(15);
    // 线条间隔, 计算得出
    const lineGap = (size / 2 - size * minPercent - lineWidth * count) / (count - 1);

    const center: PieSeriesOption['center'] = ['50%', '40%'];

    propsData.forEach((item, index) => {
      // const outer = 100 * maxPercent - index * 10 + '%';
      // const inner = 90 * maxPercent - index * 10 + '%';
      const outer = size / 2 - index * (lineWidth + lineGap) - lineWidth / 2;
      const inner = size / 2 - index * (lineWidth + lineGap) - lineWidth;

      (res.series as PieSeriesOption[]).push({
        name: item.name,
        type: 'pie',
        clockwise: false,
        radius: [outer, inner],
        center,
        label: {
          show: false
        },
        emphasis: {
          scale: false
        },
        z: 1,
        data: [
          {
            value: item.value,
            name: item.name
          },
          {
            value: total - item.value,
            name: '',
            itemStyle: {
              color: 'transparent'
            },
            ...{
              tooltip: {
                show: false
              }
            }
          }
        ]
      });

      // 背景
      (res.series as PieSeriesOption[]).push({
        name: item.name,
        type: 'pie',
        clockwise: false,
        z: 0,
        silent: true,
        animation: false,
        radius: [outer, inner],
        center,
        label: {
          show: false
        },
        emphasis: {
          scale: false
        },
        data: [
          {
            value: 7.5,
            itemStyle: {
              color: '#27435E'
            }
          },
          {
            value: 2.5,
            itemStyle: {
              color: 'rgba(0,0,0,0)'
            }
          }
        ]
      });
    });

    return res;
  }, [propsData, propsOption, total, dom]);

  const onChartReady: ChartProps['onChartReady'] = (e: echarts.ECharts) => {
    instance.current = e;
    propsOnChartReady?.(e);
    setColors(e.getOption().color as string[]);
    setDom(e.getDom());

    e.on('legendselectchanged', (event) => {
      const selected = (event as Record<string, any>).selected;
      const list: string[] = [];

      for (const key in selected) {
        if (selected[key] === true) {
          list.push(key);
        }
      }

      setSelectedLegends(list);
    });
  };

  const handleLegendClick = (item: MultiRingData) => {
    instance.current?.dispatchAction({
      type: 'legendToggleSelect',
      name: item.name
    });
  };

  return (
    <div className={cs(styles['multi-ring'], propsWrapClassName)}>
      <Chart
        className={cs(styles['chart'], propsClassName)}
        option={option}
        extra={propsExtra}
        onChartReady={onChartReady}
        {...rest}
      />

      {propsLegend ? (
        <div className={cs(styles['legend'], propsLegendClassName)}>
          {propsData.map((item, index) => {
            const selected = selectedLegends.includes(item.name);
            const percent = (item.value / total) * 100;
            const color = selected ? colors[index] : '#ccc';

            const colorNode = (
              <i
                style={{
                  display: 'inline-block',
                  width: px2rem(6),
                  height: px2rem(6),
                  borderRadius: px2rem(1),
                  background: color
                }}
              />
            );

            const legend = propsLegend({
              ...item,
              index,
              selected,
              color,
              colorNode,
              percent
            });

            return React.cloneElement(legend, {
              key: item.name,
              onClick: handleLegendClick.bind({}, item),
              onMouseEnter: () => {
                if (!instance.current) {
                  return;
                }

                instance.current.dispatchAction({
                  type: 'downplay',
                  seriesIndex: 0
                });

                instance.current.dispatchAction({
                  type: 'highlight',
                  seriesIndex: 0,
                  dataIndex: index
                });

                instance.current.dispatchAction({
                  type: 'showTip',
                  seriesIndex: 0,
                  dataIndex: index
                });
              }
            });
          })}
        </div>
      ) : null}
    </div>
  );
};

export default MultiRing;
